#include "FUSE_Functions.h"

int buscarArchivo(char*rutaArchivo,datosArchivo*data){

		fat32_directory *directorio,*ptr=	NULL;
	char*vecAux;
directorio=malloc(sizeof(fat32_directory));
	int pos=0,tamanioPath=0,posAnt=0,i;
	directorio->tipo=0;
	
	for(i=0;rutaArchivo[i]!='.'&&i<strlen(rutaArchivo);i++);
	if(i<strlen(rutaArchivo))
		memcpy((rutaArchivo+i)," ",1);
	tamanioPath=strlen(rutaArchivo);

	pos=strcspn(rutaArchivo,"/");
	posAnt=pos+1;
	leerDirectorio(directorio,FAT32.numClusterDirRoot);
	pos=strcspn(rutaArchivo+posAnt,"/");

	vecAux=malloc(sizeof(char)*pos);
	strncpy(vecAux,rutaArchivo+posAnt,pos);
    pos+=posAnt;
	
if(directorio->tipo==0)
return 3;
ptr=directorio;
	while(ptr!=NULL&&(strncmp(ptr->nombre,vecAux,pos-1))!=0)
		ptr=ptr->sig;

	free(vecAux);

	if(ptr==NULL)
		return 1;

	else{

			while(pos<tamanioPath){
				posAnt=pos+1;

				if(ptr->tipo!=DIRECTORIO)
					return 1; //no puede haber un dir en un archivo
				free(directorio);
				directorio=malloc(sizeof(fat32_directory));
				directorio->tipo=0;
				leerDirectorio(directorio,ptr->numClusterInicial);

				pos=strcspn(rutaArchivo+posAnt,"/");
				if(pos>tamanioPath)
					return 1; //falla el parseo
				vecAux=malloc(pos);
				strncpy(vecAux,rutaArchivo+posAnt,pos);

				
if(directorio->tipo==0)
return 3;
ptr=NULL;
	ptr=	directorio;
				while(ptr!=NULL&&(0!=strncmp(ptr->nombre,vecAux,pos)))
					ptr=ptr->sig;

				if(ptr==NULL)
					return 1;

				pos+=posAnt;
				free(vecAux);
			}
if(ptr->tipo==0)
return 3;
			data->numCluster=ptr->numClusterInicial;
			data->tipo=ptr->tipo;
			data->tamanioArchivo=ptr->tamanio;
return 0;
	}

	



}


/*____________________________________________________*/

int leerDatos(datosArchivo*data,char*buffer,int offset,int size){

	int indice,secXcluster,offsetCluster;
	static listaClusters *cadenaClusters=NULL;
	static listaClusters*ptr;int off=0;
	cadenaClusters=malloc(sizeof(listaClusters));
	cadenaClusters->numCluster=0;
ptr=data->lista;
	offsetCluster=0;//posicionarseEnArchivo(data,offset,cadenaClusters);
	static int clusters=0;
	if(fmod (offset,FAT32.tamanioSector) ==0){

		clusters	=(offset/FAT32.tamanioSector)/FAT32.sectoresPorCluster;
			while(clusters>1){
				ptr=ptr->sig;
				clusters--;
			}
			if((fmod(offset,8)*8)!=0)
				offsetCluster+=(fmod(offset,8)*8);
		}

		else{
		off=offset;
			while(off>0)
			off-=FAT32.tamanioSector;
			offsetCluster++;
		}

if(clusters>0)
ptr=ptr->sig;

		for(indice=0,secXcluster=0;indice<size;indice+=FAT32.tamanioSector,secXcluster++){
			if(secXcluster>=FAT32.sectoresPorCluster){
				ptr=ptr->sig;
				secXcluster=0;
			}
		//	if((size-indice)>=512)
			leerArchivoDisco(calcularPrimerSectorDelCluster(ptr->numCluster)+offsetCluster+secXcluster,buffer+indice);
		/*	else{
				char miniBuff[512];
				memset(miniBuff,0,512);
				memcpy(miniBuff,buffer+indice,size-indice);
				leerArchivoDisco(calcularPrimerSectorDelCluster(ptr->numCluster)+offsetCluster+secXcluster,miniBuff);

			}
*/
			offsetCluster=0;
		}

		/*while(cadenaClusters!=NULL){
			ptr=cadenaClusters;
		cadenaClusters=cadenaClusters->sig;
		free(ptr);}*/

		return 0;

}

/*____________________________________________________*/

int escribirArchivo(char *rutaArchivo,datosArchivo*data,const char*buffer,int offset,int size){

	int indice,secXcluster,offsetCluster,cantClustersFaltantes;
	listaClusters *cadenaClusters=NULL;
	static listaClusters*ptr;
	cadenaClusters=malloc(sizeof(listaClusters));
	cadenaClusters->numCluster=0;
	offsetCluster=0;//posicionarseEnArchivo(data,offset,cadenaClusters);
	ptr=data->lista;int clusters=0;int off=0;
	if(fmod (offset,FAT32.tamanioSector) ==0){
		clusters	=(offset/FAT32.tamanioSector)/FAT32.sectoresPorCluster;
			while(clusters>1){
				ptr=ptr->sig;
				clusters--;
			}
			if((fmod(offset,8)*8)!=0)
						offsetCluster+=(fmod(offset,8)*8);
		}
		else{
			off=offset;
			while(off>0)
			off-=FAT32.tamanioSector;
			offsetCluster++;
		}

	cantClustersFaltantes=calcularTamanioNuevo(offsetCluster,ptr->sig,size);
if(data->tamanioArchivo==0)
	cantClustersFaltantes=0;
	if(cantClustersFaltantes>0){
		if(FAT32.numClustersLibres<cantClustersFaltantes)
			return (-ENOSPC);
		int vectorLibres[cantClustersFaltantes];
		if(buscar_Clusters_libres(cantClustersFaltantes,vectorLibres)!=0)
			return (-EIO);


		else{

			while(ptr->sig!=NULL)
				ptr=ptr->sig;
if(cantClustersFaltantes>1){
			grabar_FAT(ptr->numCluster,vectorLibres[0]);
			grabar_FAT(vectorLibres[0],vectorLibres[1]);
			agregarCluster(&(vectorLibres[0]),ptr);
			for(indice=1;indice<cantClustersFaltantes-1;indice++){
				agregarCluster(&(vectorLibres[indice]),ptr);
				grabar_FAT(vectorLibres[indice],vectorLibres[indice+1]);
			}
			agregarCluster(&(vectorLibres[indice]),ptr);
			grabar_FAT(vectorLibres[indice],0xFFFFFFF);
}
else{

	grabar_FAT(ptr->numCluster,vectorLibres[0]);
				grabar_FAT(vectorLibres[0],0xFFFFFFF);
				agregarCluster(&(vectorLibres[0]),ptr);
}
		}
	}
if(clusters>0&&ptr->sig!=NULL)
ptr=ptr->sig;

		for(indice=0,secXcluster=0;indice<size;indice+=FAT32.tamanioSector,secXcluster++){
			if(secXcluster>=FAT32.sectoresPorCluster){
				ptr=ptr->sig;
				secXcluster=0;
			}
			if((size-indice)>=512)
			escribirArchivoDisco(calcularPrimerSectorDelCluster(ptr->numCluster)+offsetCluster+secXcluster,buffer+indice);
			else{
				char miniBuff[512];
				memset(miniBuff,0,512);
				memcpy(miniBuff,buffer+indice,size-indice);
				escribirArchivoDisco(calcularPrimerSectorDelCluster(ptr->numCluster)+offsetCluster+secXcluster,miniBuff);

			}

			offsetCluster=0;
		}
		//grabar_FAT(ptr->numCluster,0xFFFFFFF);

		if(((size>data->tamanioArchivo)&&(offset!=0))||((offset!=0)&&offset>=data->tamanioArchivo)||((size<data->tamanioArchivo)&&(offset!=0))){
			grabarEntradaArchivo(rutaArchivo,size+data->tamanioArchivo+(data->tamanioArchivo-offset));
			data->tamanioArchivo=size+data->tamanioArchivo+(data->tamanioArchivo-offset);
		}
		else{
			grabarEntradaArchivo(rutaArchivo,size);
			data->tamanioArchivo=size;
		}
		/*while(cadenaClusters!=NULL){
			ptr=cadenaClusters;
		cadenaClusters=cadenaClusters->sig;
		free(ptr);}*/

		return 0;
	}

/*____________________________________________________*/

int posicionarseEnArchivo(datosArchivo*data,int offset,listaClusters* cadenaClusters){

	int indice;
	int posicionEnSectores,offsetPos;
	int offsetCluster,cantClusters,posicionEnClusters;

	cantClusters=conseguirCadenaClusters(cadenaClusters,data->numCluster);
	printf("Cantidad de sclusters= %i\n",cantClusters);
	for(indice=0;(offset-indice)>0;indice+=FAT32.tamanioSector);

	posicionEnSectores=(indice/FAT32.tamanioSector)+1;
	if(indice>0)
		offsetPos=offset-(indice-FAT32.tamanioSector);
	else
		offsetPos=0;

	if((posicionEnSectores/FAT32.sectoresPorCluster)>cantClusters)
		return -ESPIPE;
	else{
		for(indice=0;(posicionEnSectores-indice)>0;indice+=FAT32.sectoresPorCluster);

		posicionEnClusters=(indice/FAT32.sectoresPorCluster);
		offsetCluster=posicionEnSectores-(indice-FAT32.sectoresPorCluster);

		for(indice=1;indice<posicionEnClusters;indice++)
			cadenaClusters=cadenaClusters->sig;
	}

	return (offsetCluster-1);

}

/*____________________________________________________*/

 int calcularTamanioNuevo(int desplazamientoCluster,listaClusters*cadenaClusters,int size){

	 int indice,resultado;
	 listaClusters*ptr=NULL;
	 ptr=cadenaClusters;
	 for(indice=0;ptr!=NULL;indice++)
		 ptr=ptr->sig;
	 resultado =   (indice * FAT32.sectoresPorCluster)- desplazamientoCluster;
int resul=0;
resul=resultado;
	resultado= (resultado*FAT32.tamanioSector )- size;

	if(resultado>0)
		return (-EINVAL);
	else{
		resul= size- (resul*FAT32.tamanioSector);
		if((fmod(resul,FAT32.tamanioSector)!=0)||(size<(FAT32.tamanioSector*FAT32.sectoresPorCluster)))
		return ((((resul /FAT32.tamanioSector))/FAT32.sectoresPorCluster)+1);
		else
			return ((((resul /FAT32.tamanioSector))/FAT32.sectoresPorCluster));
	}
}

 /*____________________________________________________*/

 int grabarEntradaArchivo(char*rutaArchivo,int nuevoTamanio){

 	fat32_directory* directorio,*ptr=NULL;
 	char*vecAux;
 	int pos,i,tamanioPath,posAnt;
 	directorio=malloc(sizeof(fat32_directory));
 	directorio->tipo=0;

	for(i=0;rutaArchivo[i]!='.'&&i<strlen(rutaArchivo);i++);
	if(i<strlen(rutaArchivo))
		memcpy((rutaArchivo+i)," ",1);
 	tamanioPath=strlen(rutaArchivo);

 	pos=strcspn(rutaArchivo,"/");
 	posAnt=pos+1;
 	leerDirectorio(directorio,FAT32.numClusterDirRoot);
 	pos=strcspn(rutaArchivo+posAnt,"/");

 	vecAux=malloc(sizeof(char)*pos);
 	strncpy(vecAux,rutaArchivo+posAnt,pos);
     pos+=posAnt;
 	ptr=directorio;
if(directorio->tipo==0)
return 1;

 	while(ptr!=NULL&&(strncmp(ptr->nombre,vecAux,pos-1)!=0))
 		ptr=ptr->sig;

 	free(vecAux);

 	if(ptr==NULL)
 		return -ENOENT;

 	else{

 			while(pos<tamanioPath){
 				posAnt=pos+1;

 				if(ptr->tipo!=DIRECTORIO)
 					return -EFAULT; //no puede haber un dir en un archivo
free(directorio);
directorio=malloc(sizeof(fat32_directory));
directorio->tipo=0;
 				leerDirectorio(directorio,ptr->numClusterInicial);

 				pos=strcspn(rutaArchivo+posAnt,"/");
 				if(pos>tamanioPath)
 					return -ESPIPE; //falla el parseo
 				vecAux=malloc(sizeof(char)*pos);
 				strncpy(vecAux,rutaArchivo+posAnt,pos);

 				ptr=directorio;
if(directorio->tipo==0)
return 1;
 				while(ptr!=NULL&&(0!=strncmp(ptr->nombre,vecAux,pos)))
 					ptr=ptr->sig;

 				if(ptr==NULL)
 					return 1;

 				pos+=posAnt;
 				free(vecAux);
 			}
 			char bufferEscritura[512];

 			leerArchivoDisco(ptr->numSectorEntrada,bufferEscritura);
 			if(ptr->LongFN)
 				ptr->offsetEntrada+=32;
 			if(nuevoTamanio>0xFF)
 				nuevoTamanio=(swap_uint32(nuevoTamanio));
 			memcpy(bufferEscritura+ptr->offsetEntrada+0x1C,&nuevoTamanio,sizeof(uint32_t));
 			escribirArchivoDisco(ptr->numSectorEntrada,bufferEscritura);
 	}

 	return 0;
 }

 /*____________________________________________________*/

 int crearArchivoDirectorio(char* rutaArchivo,datosArchivo*data,mode_t modoApertura,int creacion){

	 int offset=0;
	 int sectorIni=0;
	 int numCluster=0;
	 int indice,i;
	 datosArchivo* dataLocal=malloc(sizeof(datosArchivo));

	 for(indice=strlen(rutaArchivo);rutaArchivo[indice]!='/';indice--);
	 if(indice==0)
		 indice++;
		 char *rutaAnt=malloc(indice+1);

	 memcpy(rutaAnt,rutaArchivo,indice);

	 rutaAnt[indice]='\0';

	 if(!strcmp(rutaAnt,"/")){
		 dataLocal->numCluster=2;
		 buscarEntradaLibre(2,&sectorIni,&offset);
	 }

	 else{
		 int resultado=0;
resultado=buscarArchivo(rutaAnt,dataLocal);

		 if(resultado!=0){
	 		crearArchivoDirectorio(rutaAnt,dataLocal,modoApertura,1);
	 		buscarArchivo(rutaAnt,dataLocal);
		 }
		buscarEntradaLibre(dataLocal->numCluster,&sectorIni,&offset);
free(rutaAnt);
	 }

	 if(creacion==1){
		 if(FAT32.numClustersLibres>=1){
		int rIO= buscar_Clusters_libres(1,&numCluster);
		if(rIO!=0)
			return -EIO;
		else{
		 data->numCluster=numCluster;
		 grabar_FAT(data->numCluster,0xFFFFFFF);
		}
		 }
		 else
			 return -ENOSPC;

	 }
	 indice=strlen(rutaArchivo);
	 for(i=0;rutaArchivo[indice]!='/';indice--,i++);
	 char nombre[13];
	 memset(nombre,0,13);

	 memcpy(nombre,rutaArchivo+(strlen(rutaArchivo)-(i-1)),i-1);
	 for(indice=0;nombre[indice]!='.'&&indice<strlen(nombre);indice++);
	 if(indice<strlen(nombre))
		memcpy(nombre+indice," ",1);
	 escribirEntradaDirectorio(sectorIni,offset,nombre,data,dataLocal->numCluster);

	return 0;
}

 /*____________________________________________________*/

 int escribirEntradaDirectorio(int sector,int offset,char*nombreArchivo,datosArchivo*data,int pCluster){
	 char buffer[512];
	 leerArchivoDisco(sector,buffer);
	 uint16_t vector[26];
	 memset(vector,0,26);
	 int tamanio=0;
	 unicode_utf8_to_utf16_inbuffer(nombreArchivo,strlen(nombreArchivo),vector,&tamanio);
	 int arch=0x20;
	 int dir=0x10;
	 memset(buffer+offset,0,64);
	 memcpy(buffer+offset,"1",1);
	 if(tamanio>5){
		memset(buffer+offset+1,0,sizeof(uint16_t)*5);
		 memcpy(buffer+offset+1,vector,sizeof(uint16_t)*5);
		 if((tamanio-5)>6){
memset(buffer+offset+0x0E,0,sizeof(uint16_t)*6);
			 memcpy(buffer+offset+0x0E,vector+5,sizeof(uint16_t)*6);
 memset(buffer+offset+0x1C,0,sizeof(uint16_t)*2);
			 memcpy(buffer+offset+0x1C,vector+5+6,sizeof(uint16_t)*2);
		 }
		 else{
 memset(buffer+offset+0x0E,0,sizeof(uint16_t)*(tamanio-5));
			 memcpy(buffer+offset+0x0E,vector+5,sizeof(uint16_t)*(tamanio-5));
}
	 }
	 else{
memset(buffer+offset+1,0,sizeof(uint16_t)*tamanio);
		 memcpy(buffer+offset+1,vector,sizeof(uint16_t)*tamanio);

}
	 int lfn = 0x0F;
	 memcpy(buffer+offset+11,&lfn,1);
	 if(strlen(nombreArchivo)>11){
memset(buffer+offset+32,0,11);
		 memcpy(buffer+offset+32,nombreArchivo,7);
		 memcpy(buffer+offset+32+7,"~",1);
		 int i;
		 for(i=0;i<strlen(nombreArchivo)&& nombreArchivo[i]!=' ';i++);
			if(i<strlen(nombreArchivo))
				memcpy(buffer+offset+32+8,nombreArchivo+(strlen(nombreArchivo)-3),3);
	 }
	 else{
		  int i;
	 for(i=0;i<strlen(nombreArchivo)&& nombreArchivo[i]!=' ';i++);
	if(i<strlen(nombreArchivo)){
	 memcpy(buffer+offset+32,nombreArchivo,strlen(nombreArchivo)-3);
	 memcpy(buffer+offset+32+8,nombreArchivo+(strlen(nombreArchivo)-3),3);
	}
	else
		memcpy(buffer+offset+32,nombreArchivo,strlen(nombreArchivo));
	 }


	 if(data->tipo==DIRECTORIO){
		 memcpy(buffer+offset+32+11,&(dir),1);
		int sectorDir= calcularPrimerSectorDelCluster(data->numCluster);
		char bufferDir[512];
		leerArchivoDisco(sectorDir,bufferDir);
		int punt=0x2E;
		memset(bufferDir,0,64);
		memcpy(bufferDir,&(punt),1);
		memcpy(bufferDir+11,&(dir),1);
		memcpy(bufferDir+32,&(punt),1);
		memcpy(bufferDir+32+1,&(punt),1);
		memcpy(bufferDir+11+32,&(dir),1);
		char vecAux[4];
		uint32_t num=pCluster;
		memset(vecAux,0,4);

		 if(pCluster>0xFF){
		 				 num=(swap_uint32(num));
		 				 memcpy(vecAux,&num,sizeof(uint32_t));
		 				 memcpy(bufferDir+32+0x1A,vecAux,sizeof(uint16_t));
		 				 memcpy(bufferDir+32+0x14,vecAux+2,sizeof(uint16_t));
		 }
		 			 else{
		 				 memcpy(vecAux,&num,sizeof(uint32_t));
		 				 memcpy(bufferDir+32+0x1A,vecAux,sizeof(uint16_t));
		 				 memcpy(bufferDir+32+0x14,vecAux+2,sizeof(uint16_t));
		 			 }
		if(data->numCluster>0xFF){

				 memset(vecAux,0,4);
				 uint32_t nuevoTamanio=(swap_uint32(data->numCluster));
				 memcpy(vecAux,&nuevoTamanio,sizeof(uint32_t));
				 memcpy(bufferDir+0x1A,vecAux,sizeof(uint16_t));
				 memcpy(bufferDir+0x14,vecAux+2,sizeof(uint16_t));
				 }
			 else{
				 memcpy(vecAux,&data->numCluster,sizeof(uint32_t));
				 memcpy(bufferDir+0x1A,vecAux,sizeof(uint16_t));
				 memcpy(bufferDir+0x14,vecAux+2,sizeof(uint16_t));
			 }

		escribirArchivoDisco(sectorDir,bufferDir);
	 }
	 else
		 memcpy(buffer+offset+32+11,&(arch),1);

	 if(data->tamanioArchivo>0xFF){
		 uint32_t nuevoTamanio=(swap_uint32(data->tamanioArchivo));
	 	 memcpy(buffer+offset+32+0x1C,&nuevoTamanio,sizeof(uint32_t));
	 }
	 else
		 memcpy(buffer+offset+32+0x1C,&(data->tamanioArchivo),sizeof(uint32_t));
	 char vecAux[4];
	 if(data->numCluster>0xFF){

		 memset(vecAux,0,4);

		 uint32_t nuevoTamanio=0;
		 nuevoTamanio =(swap_uint32(data->numCluster));
		 memcpy(vecAux,&nuevoTamanio,sizeof(uint32_t));
		 memcpy(buffer+offset+32+0x1A,vecAux,sizeof(uint16_t));
		 memcpy(buffer+offset+32+0x14,vecAux+2,sizeof(uint16_t));
		 }
	 else{
		 memcpy(vecAux,&data->numCluster,sizeof(uint32_t));
		 memcpy(buffer+offset+32+0x1A,vecAux,sizeof(uint16_t));
		 memcpy(buffer+offset+32+0x14,vecAux+2,sizeof(uint16_t));
	 }

	 escribirArchivoDisco(sector,buffer);
	 return 0;
 }

 /*____________________________________________________*/

 int borrarEntradaDir(char*rutaArchivo){
int borrado=0xE5;
  	
		fat32_directory *directorio,*ptr=	NULL;
	char*vecAux;
directorio=malloc(sizeof(fat32_directory));
	int pos=0,tamanioPath=0,posAnt=0,i;
	directorio->tipo=0;
	
	for(i=0;rutaArchivo[i]!='.'&&i<strlen(rutaArchivo);i++);
	if(i<strlen(rutaArchivo))
		memcpy((rutaArchivo+i)," ",1);
	tamanioPath=strlen(rutaArchivo);

	pos=strcspn(rutaArchivo,"/");
	posAnt=pos+1;
	leerDirectorio(directorio,FAT32.numClusterDirRoot);
	pos=strcspn(rutaArchivo+posAnt,"/");

	vecAux=malloc(sizeof(char)*pos);
	strncpy(vecAux,rutaArchivo+posAnt,pos);
    pos+=posAnt;
	
if(directorio->tipo==0)
return 3;
ptr=directorio;
	while(ptr!=NULL&&(strncmp(ptr->nombre,vecAux,pos-1))!=0)
		ptr=ptr->sig;

	free(vecAux);

	if(ptr==NULL)
		return 1;

	else{

			while(pos<tamanioPath){
				posAnt=pos+1;

				if(ptr->tipo!=DIRECTORIO)
					return 1; //no puede haber un dir en un archivo

				free(directorio);
				directorio=malloc(sizeof(fat32_directory));
				directorio->tipo=0;
				leerDirectorio(directorio,ptr->numClusterInicial);

				pos=strcspn(rutaArchivo+posAnt,"/");
				if(pos>tamanioPath)
					return 1; //falla el parseo
				vecAux=malloc(pos);
				strncpy(vecAux,rutaArchivo+posAnt,pos);

				
if(directorio->tipo==0)
return 3;
ptr=directorio;
				while(ptr!=NULL&&(0!=strncmp(ptr->nombre,vecAux,pos)))
					ptr=ptr->sig;

				if(ptr==NULL)
					return 1;

				pos+=posAnt;
				free(vecAux);
			}
if(ptr->tipo==0)
return 3;
  			char bufferEscritura[512];

  			leerArchivoDisco(ptr->numSectorEntrada,bufferEscritura);
  			
  			memcpy(bufferEscritura+ptr->offsetEntrada,&borrado,sizeof(uint8_t));
  			escribirArchivoDisco(ptr->numSectorEntrada,bufferEscritura);
  	}

  	return 0;
  }
